home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 February / Macworld (1999-02).dmg / Cinema 4D GO demo / Gumption Plug-ins / Plug-ins / Freeware / ShrinkWrap / ShrinkWrap.cof
Text File  |  1998-05-03  |  6KB  |  254 lines

  1. /*
  2.     The Shrinkwrap plugin wraps a closed polygon mesh, more or less like a rubber sheet,
  3.     around a group of perfect spheres (sorry, spheres only).
  4.     Send comments, praise, money :-) etc. to:
  5.     
  6.     Jim Hasselbrook
  7.     hassel@bellatlantic.net
  8.     
  9.     This software is provided free, AS IS. Feel free to modify it for any non-commercial purposes.
  10. */
  11.  
  12.  
  13.  
  14. copy(doc, obj, newname)
  15. {
  16.     var i;
  17.     
  18.     var pcount = obj->GetPointCount();
  19.     var ecount = obj->GetEdgeCount();
  20.     var tcount = obj->GetTriangleCount();
  21.     var qcount = obj->GetQuadrangleCount();
  22.  
  23.     var newobj = doc->NewPolygonObject(newname, NULL, NULL, pcount, ecount, tcount, qcount);
  24.  
  25.     var t = new(Triangle);
  26.     var q = new(Quadrangle);
  27.     var e = new(Edge);
  28.     
  29.     var mat = new(Matrix);
  30.     obj->GetMg(mat);            // obj to world coords
  31.     
  32.     for (i=0; i<pcount; i++) {
  33.         //StatusSetBar(i*100.0/pcount, TRUE);
  34.         newobj->SetPoint(i, mat->MulP(obj->GetPoint(i)));
  35.     }
  36.     
  37.     for (i=0; i<ecount; i++) {
  38.         //StatusSetBar(i*100.0/ecount, TRUE);
  39.         obj->GetEdge(i, e);
  40.         newobj->SetEdge(i, e);
  41.     }
  42.     
  43.     for (i=0; i<tcount; i++) {
  44.         //StatusSetBar(i*100.0/tcount, TRUE);
  45.         obj->GetTriangle(i, t);
  46.         newobj->SetTriangle(i, t);
  47.     }
  48.     
  49.     for (i=0; i<qcount; i++) {
  50.         //StatusSetBar(i*100.0/qcount, TRUE);
  51.         obj->GetQuadrangle(i, q);
  52.         newobj->SetQuadrangle(i, q);
  53.     }
  54.     
  55.     if (GetC4DVersion() >= 5003)
  56.     {
  57.         newobj->Optimize(TRUE,TRUE,TRUE,TRUE);
  58.     }
  59.     newobj->UpdateObject();
  60.     return newobj;
  61. }
  62.  
  63. isOutsideBoundary(p, bound)
  64. {
  65.     var obj;
  66.     var origin, bbox;
  67.     
  68.     for (obj = bound->GetDown(); obj != NULL; obj = obj->GetNext())
  69.     {
  70.         origin = obj->GetPosition();
  71.         bbox = obj->GetBox2();
  72.         if (vlen(p-origin) <= bbox.x) return obj;
  73.     }
  74.     
  75.     return NULL;
  76. }
  77.  
  78. doShrink(doc, newobj, boundgrp, iter, vacuum)
  79. {
  80.     var i, j;    
  81.     var pcount = newobj->GetPointCount();
  82.     var tcount = newobj->GetTriangleCount();
  83.     var grad = new(array, pcount);
  84.     var norms = new(array, pcount);
  85.     var edges = new(array, pcount);
  86.     var ta = new(array, tcount);
  87.     var tb = new(array, tcount);
  88.     var tc = new(array, tcount);
  89.     var p = new(array, pcount);
  90.     var t = new(Triangle);
  91.     var new_point;
  92.     var vzero = vector(0.0, 0.0, 0.0);
  93.  
  94.     /* copying the data into arrays seems faster
  95.      * than calling the accessors over and over
  96.      */
  97.      
  98.     for (i=0; i<pcount; i++)
  99.     {
  100.         p[i] = newobj->GetPoint(i);
  101.         grad[i] = vzero;
  102.         norms[i] = vzero;
  103.         edges[i] = 0;
  104.     }
  105.     
  106.     for (i=0; i<tcount; i++)
  107.     {
  108.         newobj->GetTriangle(i, t);
  109.         ta[i] = t->a;
  110.         tb[i] = t->b;
  111.         tc[i] = t->c;
  112.     }
  113.  
  114.     var a_i, b_i, c_i;
  115.     var ab, bc, ca, norm;
  116.     var ab_squared, bc_squared, ca_squared;
  117.     
  118.     for (j=0; j<iter; j++)
  119.     {
  120.         StatusSetBar(j*100.0/iter, TRUE);
  121.         //StatusSetText("Calculating gradients", TRUE);
  122.     
  123.         for (i=0; i<tcount; i++)
  124.         {
  125.             a_i = ta[i]; b_i = tb[i]; c_i = tc[i];
  126.             ab = p[a_i] - p[b_i];
  127.             bc = p[b_i] - p[c_i];
  128.             ca = p[c_i] - p[a_i];
  129.  
  130.             ab_squared = vnorm(ab) * vlen(ab) * vlen(ab);
  131.             bc_squared = vnorm(bc) * vlen(bc) * vlen(bc);
  132.             ca_squared = vnorm(ca) * vlen(ca) * vlen(ca);
  133.             
  134.             grad[a_i] += ca_squared - ab_squared; edges[a_i] += 2;
  135.             grad[b_i] += ab_squared - bc_squared; edges[b_i] += 2;
  136.             grad[c_i] += bc_squared - ca_squared; edges[c_i] += 2;
  137.  
  138.             norm = vcross(ca, ab);
  139.             norms[a_i] += norm;
  140.             norms[b_i] += norm;
  141.             norms[c_i] += norm;
  142.  
  143.         }
  144.         
  145.         //StatusSetText("Moving points", TRUE);
  146.         for (i=0; i<pcount; i++)
  147.         {
  148.             //StatusSetBar(i*100.0/pcount, TRUE);
  149.             new_point = p[i] + vnorm(grad[i]) * sqrt(vlen(grad[i])) / edges[i]
  150.                              - (vnorm(norms[i]) * sqrt(vlen(norms[i])) / edges[i]) * vacuum / 2.0;
  151.             var boundobj = isOutsideBoundary(new_point, boundgrp);
  152.             if (boundobj == NULL)
  153.             {
  154.                 p[i] = new_point;
  155.             }
  156.             else    // place along surface
  157.             {
  158.                 var origin = boundobj->GetPosition();
  159.                 var bbox = boundobj->GetBox2();
  160.                 p[i] = origin + vnorm(new_point - origin) * bbox.x;
  161.             }
  162.              newobj->SetPoint(i, p[i]);
  163.             grad[i] = vzero;
  164.             norms[i] = vzero;
  165.             edges[i] = 0;
  166.         }
  167.     
  168.         doc->RedrawAll(FALSE, FALSE, FALSE);
  169.     }
  170.     
  171.     newobj->UpdateObject();
  172.     
  173.     return newobj;
  174. }
  175.  
  176. /*
  177.  * Create a flattened list of boundary objects,
  178.  * translated to world coordinates
  179.  */
  180.  
  181. copyBounds(doc, boundgrp, boundtemp, last)
  182. {
  183.     var obj, newobj;
  184.     var mg = new(Matrix);
  185.     
  186.     for (obj = boundgrp->GetDown(); obj != NULL; obj = obj->GetNext())
  187.     {
  188.         newobj = doc->CopyObject(obj, boundtemp, last, COPY_NO_HIERARCHY);
  189.         obj->GetMg(mg);
  190.         newobj->SetMg(mg);
  191.         
  192.         last = copyBounds(doc, obj, boundtemp, newobj);
  193.     }
  194.     return last;
  195. }
  196.  
  197. shrink(doc)
  198. {
  199.     var obj, newobj;
  200.     var mg = new(Matrix);
  201.     
  202.     obj = doc->FindFirstActiveObject();
  203.     
  204.     if(!obj || !instanceof(obj,PolygonObject)) 
  205.     {
  206.         TextDialog("Must select a polygon object!", DLG_OK);
  207.         return;
  208.     }
  209.     
  210.     var d = new (SimpleDialog);
  211.  
  212.     d->SetData(0,"Boundary Group",FIELD_STRING,0.0,0.0,"Object group");
  213.     d->SetData(1,"Iterations",FIELD_INTEGER,1,100,1);
  214.     d->SetData(2,"Vacuum (-1.0 to 2.0)",FIELD_FLOAT,-1.0,2.0,0.0);
  215.     d->SetTitle("Shrink Wrap");
  216.  
  217.     if (!d->DoDialog()) return FALSE;
  218.  
  219.     var boundgrp = doc->FindObject(d->GetData(0));
  220.     var iter = d->GetData(1);
  221.     var vacuum = d->GetData(2);
  222.     
  223.     if(!boundgrp || !boundgrp->GetDown()) 
  224.     {
  225.         TextDialog("Must select a boundary group!", DLG_OK);
  226.         return;
  227.     }
  228.     
  229.     if(obj->GetQuadrangleCount() > 0) 
  230.     {
  231.         TextDialog("Please triangulate first!", DLG_OK);
  232.         return;
  233.     }
  234.     
  235.     newobj = copy(doc, obj, obj->GetName());
  236.     doc->KillObject(obj);
  237.     doc->ActivateObject(newobj);
  238.     
  239.     var boundtemp = doc->NewPolygonObject("temp bound group", NULL, NULL, 0, 0, 0, 0);
  240.     copyBounds(doc, boundgrp, boundtemp, NULL);
  241.     
  242.     doShrink(doc, newobj, boundtemp, iter, vacuum);
  243.     
  244.     doc->KillObject(boundtemp);
  245.     
  246.     doc->SendMessage(DOCUMENT_CHANGED);
  247.     StatusClear();
  248. }
  249.  
  250. main()
  251. {
  252.     RegisterMenuHook("Shrinkwrap","shrink");
  253. }
  254.